﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using HtmlAgilityPack;
using MiniCrawler;
using MiniCrawler.Business.Collectors;
using MiniCrawler.Business.Collectors.LinkCollectors;
using MiniCrawler.DataAccess;
using MiniCrawler.Entity;
using MiniCrawler.Logging;

namespace MiniCrawler.Business
{
    class SoHoaVnExpress : ILinkCollector
    {
        private DateTime start;

        private string url = "http://sohoa.vnexpress.net/";
        private string hostName = "http://sohoa.vnexpress.net/";
        private string sampleCategoryLink = 
            "http://vnexpress.net/tin-tuc/the-gioi/cuoc-song-do-day";
        private string sampleNewsLink =
            "http://vnexpress.net/tin-tuc/the-gioi/nguoi-viet-5-chau/nghe-nhac-xua-o-little-saigon-2862164.html";

        private List<string> CategoryPatterns = 
            new List<string>
            {
                "http://sohoa.vnexpress.net/*/page/*.html", 
                "http://sohoa.vnexpress.net/*/*/page/*.html"
            };

        private List<string> NewsPatterns =
            new List<string>
            {
                "http://sohoa.vnexpress.net/*/*.html", 
                "http://sohoa.vnexpress.net/*/*/*.html"
            };

        public int GetAllCategoryLinks(List<string> allLinks)
        {
            try
            {
                if (allLinks.Count > 0)
                {
                    foreach (var link in allLinks)
                    {
                        if (IsCategoryLink(link) && !DataLinkHelper.IsLinkExist(link))
                        {

                            var newLink = new DataLink
                                {
                                    DateCreated = DateTime.Now,
                                    IsChecked = false,
                                    Level = 1,
                                    Value = link,
                                    Website = hostName
                                };

                                DataLinkHelper.CreateLink(newLink);
                            
                        }
                    }
                }
                return 1;
            }
            catch (Exception ex)
            {
                LogService.Service.Error(ex);
                return -1;
            }

        }

        public int GetAllNewsLink(List<string> allLinks)
        {
            try
            {
                if (allLinks.Count > 0)
                {
                    foreach (var link in allLinks)
                    {

                        if (IsDataLink(link) && !DataLinkHelper.IsLinkExist(link))
                        {
                            var newLink = new DataLink
                            {
                                DateCreated = DateTime.Now,
                                IsChecked = false,
                                Level = 2,
                                Value = link,
                                Website = hostName
                            };

                            DataLinkHelper.CreateLink(newLink);
                        }
                    }
                }
                return 1;
            }
            catch (Exception ex)
            {
                LogService.Service.Error(ex);
                return -1;
            }

        }

        public void Run()
        {
            
        }

        public void Run(string runningState)
        {
            try
            {

                if(runningState.Equals("CollectingLinks"))
                {
                    CollectingLinks();
                }
                else if(runningState.Equals("CollectingData"))
                {
                    CollectingData();
                }
            }
            catch (Exception ex)
            {
                LogService.Service.Error(ex);
            }

        }

        public void CollectingLinks()
        {
            try
            {
                //return;
                start = DateTime.Now;

                string html = Common.GetWebPage(url);

                var s = 0;
                var t0 = Utils.GetAllLinks(html);

                // Get from homepage

                GetAllCategoryLinks(t0);

                Log.WriteElapseTime(start);

                GetAllNewsLink(t0);

                Log.WriteElapseTime(start);

                // Scan cat link
                while (DataLinkHelper.HasUncheckedLinks(1))
                {

                    var catLink = DataLinkHelper.SelectUncheckedLinks(1)[0];
                    
                    Log.WriteLog("[CATEGORY : " + DataLinkHelper.SelectLinks(1).Count + "][UNCHECKED : " + DataLinkHelper.SelectUncheckedLinks(1).Count + "]");
                    Log.WriteLog("[NEWS     : " + DataLinkHelper.SelectLinks(2).Count + "][UNCHECKED : " + DataLinkHelper.SelectUncheckedLinks(2).Count + "]");

                    string cathtml = Common.GetWebPage(FillAbsoluteUrl(hostName, catLink.Value));

                    GetAllCategoryLinks(Utils.GetAllLinks(cathtml));
                    GetAllNewsLink(Utils.GetAllLinks(cathtml));

                    catLink.IsChecked = true;
                    DataLinkHelper.UpdateLink(catLink);

                    Log.WriteElapseTime(start);
                }

            }
            catch (Exception ex)
            {
                LogService.Service.Error(ex);
            }
        }

        public void CollectingData()
        {
            while (DataLinkHelper.HasUncheckedLinks(2))
            {

                var catLink = DataLinkHelper.SelectUncheckedLinks(2)[0];
                    
                Log.WriteLog("[CATEGORY : " + DataLinkHelper.SelectLinks(1).Count + "][UNCHECKED : " + DataLinkHelper.SelectUncheckedLinks(1).Count + "]");
                Log.WriteLog("[NEWS     : " + DataLinkHelper.SelectLinks(2).Count + "][UNCHECKED : " + DataLinkHelper.SelectUncheckedLinks(2).Count + "]");

                GetNewsContent(catLink.Value);

                Log.WriteElapseTime(start);
            }
        }

        public string FillAbsoluteUrl(string hostName, string url)
        {
            if (url.StartsWith("/")) return hostName + url;

            else return url;
        }

        public bool IsCategoryLink(string link)
        {
            return false;
        }

        public bool IsDataLink(string link)
        {

            return false;
        }


        private static bool IsNumeric(string number)
        {
            int t = -1;
            var x = int.TryParse(number, out t);
            return x;
        }

        public static string CreatePath(string name)
        {
            string strNewName = name;

            #region Replace unicode chars
            Regex regex = new Regex("\\p{IsCombiningDiacriticalMarks}+");
            string temp = name.Normalize(NormalizationForm.FormD);
            strNewName = regex.Replace(temp, String.Empty).Replace('\u0111', 'd').Replace('\u0110', 'D');
            #endregion

            #region Replace special chars
            string strSpecialString = "~\"“”#%&*:;<?/\\{|}.+_@$^()[]`,!";

            foreach (char c in strSpecialString.ToCharArray())
            {
                strNewName = strNewName.Replace(c, ' ');
            }
            #endregion

            #region Replace space

            // Create the Regex.
            var r = new Regex(@"\s+");
            // Strip multiple spaces.
            strNewName = r.Replace(strNewName, @" ");
            strNewName = strNewName.Replace(">", "/");
            strNewName = strNewName.Trim();

            #endregion

            return strNewName;
        }

        public void GetNewsContent(string link)
        {
            try
            {
                if (link.StartsWith("/")) link = hostName + link;

                string html = Common.GetWebPage(link);
                NewsData n = new NewsData();
                if (!string.IsNullOrEmpty(html))
                {

                    string mhtml = html;
                    var doc = new HtmlDocument();
                    doc.LoadHtml(mhtml);

                    var titleNode = doc.DocumentNode.SelectSingleNode("//div[@id='wrap']/div[@id='content']/div[@class='wrapCT']/div[@class='left']/div[@class='detail']/div[@class='dt-left']/div[@id='print_content']/h1[@class='dt-ptit']");
                    if (titleNode == null)
                        titleNode =
                            doc.DocumentNode.SelectSingleNode(
                                "/html/body/div[@id='wrap']/div[@id='content']/div[@class='wrapCT']/div[@class='left']/div[@class='vote-detail']/div[@class='vote-detail']/div[@class='vd-ct']/div[@class='vd-tit']/h1[@class='vd-ptit']");

                    if (titleNode == null)
                        titleNode =
                            doc.DocumentNode.SelectSingleNode(
                                "/html/body/div[@id='wrap']/div[@id='content']/div[@class='wrapCT']/div[@class='upVideo']/div[@class='leftUpV']/div[@class='topVideo']/div[@class='ctTopVideo']/h1[@class='h3TopVideo']/a");

                    n.Title = Utils.GetInnerText(titleNode);
                    n.Url = link;

                    var contentNode =
                        doc.DocumentNode.SelectSingleNode("//div[@id='wrap']/div[@id='content']/div[@class='wrapCT']/div[@class='left']/div[@class='detail']/div[@class='dt-left']/div[@id='print_content']/div[@id='article_content']");

                    if (contentNode == null)
                    {
                        contentNode =
                            doc.DocumentNode.SelectSingleNode(
                                "/html/body/div[@id='wrap']/div[@id='content']/div[@class='wrapCT']/div[@class='left']/div[@class='vote-detail']/div[@class='vote-detail']/div[@class='vd-ct']/div[@class='most-dt']/div[@id='votes']/div[@class='dtab-left']/div[@id='article_content']");
                    }
                    // Get image

                    if(contentNode != null)
                    {
                        List<string> links = Utils.ExtractImageLinksFromHtml(contentNode.InnerHtml);

                        if (links != null && links.Count > 0)
                        {
                            if (links[0] != null)
                            {
                                n.ImageUrl = links[0];
                                n.Image = "\\SoHoaVnExpress\\" + Path.GetFileName(links[0]);
                            }
                        }
                        if (!string.IsNullOrEmpty(n.ImageUrl))
                        {
                            DownloadFiles(n.ImageUrl, "\\SoHoaVnExpress\\");
                        }
                    }

                    
                    NewsHelper.AddNews(n);

                    DataLinkHelper.UpdateLink(link);
                }
            }
            catch (Exception ex)
            {
                LogService.Service.Error(ex);
            }

        }


        public void RemoveNode(HtmlNode root, HtmlNode node)
        {
            try
            {

                if (node.ParentNode == root)
                {
                    root.RemoveChild(node);
                }
                else
                {
                    node.Remove();
                }
            }
            catch (Exception ex)
            {
                var flag = 0;
            }
        }
        
        private void DownloadFiles(string url, string folder)
        {

            try
            {
                string s = "D:\\DownloadFiles\\";
                Directory.CreateDirectory(s + folder);
                string fileName = Path.GetFileName(url);

                WebClient webClient = new WebClient();
                webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
                webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);

                Log.WriteLog("[DOWNLOADING][" + url + "]");
                webClient.DownloadFileAsync(new Uri(url), @s + folder + "/" + fileName);
            }
            catch (Exception ex)
            {
                LogService.Service.Error("FAILED TO DOWNLOAD FILES");
                LogService.Service.Error("Folder : " + folder);
                LogService.Service.Error("File : " + url);
                throw;
            }

        }

        private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            Log.WriteCurrent("[DOWNLOADING : " + e.ProgressPercentage);
        }

        private void Completed(object sender, AsyncCompletedEventArgs e)
        {
            Log.WriteLog("[DOWNLOAD COMPLETE]");
        }
    }
}
